#!/usr/bin/env python
# coding:utf-8
from PoboAPI import *
import datetime
import numpy as np
import math
import pandas as pd

#开始时间，用于初始化一些参数
def OnStart(context) :
    print("I\'m starting...")
    #设置全局交易品种
    g.code = GetMainContract('CFFEX','IF',20)
    #设置全局变量
    g.count=0
    g.N1=26
    g.N2=7
    g.Alpha=5
    g.AF=0.02
    g.SAR=0
    g.derection='close'
    g.j0=GetCurrentTime()
    #订阅行情
    SubscribeQuote(g.code)
    #设置闹钟
    context.MyAlarm = SetAlarm(datetime.time(14, 59), RepeatType.Daily)
    #登录期货账号
    if "回测期货" in context.accounts:
        print("登录交易账号 回测期货")
        if context.accounts["回测期货"].Login() :
            context.myacc = context.accounts["回测期货"]

#开盘事件            
def OnExchangeOpen(context, accountname, exchangecode, productcode):
    if exchangecode == 'CFFEX':
      cutime = GetCurrentTime()
      if str(cutime)[12:]=='9:30:00':
        #在每日开盘时将g.count初始化为0
        g.count=0

#闹钟事件
def OnAlarm(context, alarmid):
    print("每日收盘前平仓")
    #每日收盘前平仓
    option = PBObj()
    option.contract = g.code
    pos = context.myacc.GetPositions(option)
    price_type=PriceType(PbPriceType.Limit,limit_price_type=2)
    for p in pos:
      if p.bstype.BuySellFlag=="0":
        QuickInsertOrder(context.myacc,g.code,'sell','close',price_type,p.volume)
      if p.bstype.BuySellFlag=="1":
        QuickInsertOrder(context.myacc,g.code,'buy','close',price_type,p.volume)
    g.derection='close'
    
def OnQuote(context,code) :
    #每5分钟执行一次
    if g.count%5==0:
        print("调用到OnQuote事件")
        #获取当前主力合约
        Maincontract=GetMainContract('CFFEX','IF',20)
        #若主力合约发生更换，将交易品种换成新的主力合约
        if g.code != Maincontract:
            UnsubscribeQuote(g.code)
            g.code=Maincontract
            SubscribeQuote(g.code)
        print("当前交易品种为"+str(g.code))
        #获取当前时间
        cutime = GetCurrentTime()
        dfd=GetHisDataByFieldAsDF(g.code, ['high', 'low'], bar_type=BarType.Min5, end_date=cutime,count=g.N1)
        #计算vH,vL
        vH=max(dfd['high'])
        vL=min(dfd['low'])
        #计算近N2期的波动率的最小值
        d=list(GetHisDataByFieldAsDF(g.code, ['close'], bar_type=BarType.Min,end_date=cutime,count=g.N2)['close'])
        dlist=[]
        for i in range(0,len(d)-5,5):
            dlist.append(d[i:i+5])
        vlist=[]
        for l in dlist:
            vlist.append(pd.Series(l).std())
        vol=min(vlist)
        #下单类型
        price_type=PriceType(PbPriceType.Limit,limit_price_type=2)
        #设置风险度
        value = 0.6
        context.myacc.SetRiskDegreeMaxThreshold(value)
        isOver=context.myacc.IsRiskDegreeOverMax()
        #获取最新价
        dyndata = GetQuote(g.code)
        now=dyndata.now
        if now>=vH: 
        #市场每突破一次，g.AF增加0.02
            if g.AF<0.2:
                g.AF=g.AF+0.02   
            v=int(math.ceil(0.6*context.myacc.GetValidVolume(g.code, BSType.BuyOpen,now)))
            if vol<g.Alpha:
              #若没超过风险度
              if isOver==False:
                  #开多仓
                  QuickInsertOrder(context.myacc,g.code,'buy','open',price_type,v)
                  g.j0=cutime
                  g.SAR=np.array(dfd['low'])[-1]
                  g.AF=0.02
                  g.derection='buy'
                  print("买入"+str(v)+str(g.code))
        if now<=vL:
            if g.AF<0.2:
                g.AF=g.AF+0.02  
            v=int(math.ceil(0.6*context.myacc.GetValidVolume(g.code, BSType.SellOpen,now)))
            if vol<g.Alpha:
                #若没超过风险度
                if isOver==False:
                    #开空仓
                    QuickInsertOrder(context.myacc,g.code,'sell','open',price_type,v)
                    g.j0=cutime
                    g.vc=np.array(dfd['high'])[-1]
                    g.AF=0.02
                    g.derection='sell'
                    print("卖出"+str(v)+str(g.code))
        #获取持仓状况
        option = PBObj()
        option.contract = g.code
        pos = context.myacc.GetPositions(option)
        #多仓止损
        if now<=g.SAR and g.derection=='buy':
            for p in pos:
                QuickInsertOrder(context.myacc,g.code,'sell','close',price_type,p.volume)
                g.derection='close'
        #空仓止损
        if now>=g.SAR and g.derection=='sell':
            for p in pos:
                QuickInsertOrder(context.myacc,g.code,'buy','close',price_type,p.volume)
                g.derection='close'
        #获取开仓时间到现在的最高价最低价数据
        h=GetHisDataByFieldAsDF(g.code, ['high', 'low'], bar_type=BarType.Min5, start_date=g.j0, end_date=cutime)
        highlist=list(h['high'])
        lowlist=list(h['low'])
        h_two=highlist[-2:]
        l_two=lowlist[-2:]
        #更新g.SAR
        if g.derection=='buy':
            if highlist:
                g.SAR=min(min(l_two),g.SAR+(max(highlist)-g.SAR)*g.AF)
        if g.derection=='sell':
            if lowlist:
                g.SAR=max(max(h_two),g.SAR-(g.SAR-min(lowlist))*g.AF)
    g.count=g.count+1